package com.daydreamdev.secondskill.middle.rabbit2;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.Headers;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Map;

@Component
@Slf4j
public class RabbitReceiver { //消费者
    int count = 0;

    //死信队列 的处理方式 https://blog.csdn.net/doupengzp/article/details/106929216
    @RabbitListener(queues = RabbitConfig.dlQueue, containerFactory = "testFactory1")
    //public void testHandler(List<Message> messages, Channel channel)
    public void reciveDeadLetter(Message message, Channel channel, @Headers Map<String, Object> headers) throws IOException {
        long deliveryTag = (Long) headers.get(AmqpHeaders.DELIVERY_TAG);
        try {
            System.out.println("死信队列消费者收到消息 : " + new String(message.getBody(), "UTF-8"));
            /**
             * 手动确认ack模式下，如果消费者去队列中取到了消息，但是没有手动确认，所以消息会在队列中继续存在，
             * 程序重启后会再次消费这些消息，直到程序手动确认消息。如果手动确认了消息那么队列中的这条消息会立即被删除。
             * 手动ack
             * deliveryTag:该消息的index
             * multiple：是否批量.true:将一次性ack所有小于deliveryTag的消息。
             */
            channel.basicAck(deliveryTag, false);
        } catch (Exception e) {
            //消息退回 (可以在可视化界面看到)
            //批量退回 退回之后重回消息队列 true  false的话就是丢弃这条信息，如果配置了死信队列，那这条消息会进入死信队列
            channel.basicNack(deliveryTag, false, true);
            //单条退回 channel.basicReject();
        }
    }

    //注意： 重试并不是 RabbitMQ 重新发送了消息到了队列，仅仅是消费者内部进行了重试，换句话说就是重试跟mq没有任何关系。
    // 上述消费者代码不能添加try{}catch(){}，一旦捕获了异常，在自动 ack 模式下，就相当于消息正确处理了，消息直接被确认掉了，
    // 不会触发重试的。 当然并不是说不能添加 try{}catch(){}，而是不能将异常给处理了。可以如下写：
    @RabbitListener(queues = "${mq.queueBinding.queue}")
    public void infoConsumption(String data, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws Exception {
        log.info("重试次数 = {}", count++);
        try {
            // 处理主要业务
            int i = 10 / 0;
        } catch (Exception e) {
            // 处理业务失败，还要进行其他操作，比如记录失败原因
            log.info("记录失败原因 ====>" + e.getMessage());
            throw new RuntimeException("手动抛出" + e.getMessage());
        }
        channel.basicAck(tag, false);
    }

    // //测试重试
    // @RabbitListener(queues = "${mq.queueBinding.queue}")
    // public void infoConsumption(String data, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws Exception {
    //     log.info("重试次数 = {}", count++);
    //     int i = 10 / 0;
    //     channel.basicAck(tag, false);
    // }
}